﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIObjects.TreeViewInterfaces;
using System.Collections.ObjectModel;
using TreeBuilder.Contracts;
using MvvmTreeView;
using System.Windows.Controls;
using System.Diagnostics;
using AbstraX.ClientInterfaces;
using System.Windows;
using SL4PopupMenu;
using System.ComponentModel;
using SW = Microsoft.Windows;

namespace TreeBuilder.ViewModels
{
    public class TreeBuilderTreeNodePropertyBinding : TreeBuilderTreeNodeImageNode
    {
        private ITreeNodePropertyBinding propertyBinding;
        private bool allowDrop;
        public override event PropertyChangedEventHandler PropertyChanged;

        public TreeBuilderTreeNodePropertyBinding(ITreeBuilderService treeBuilderService, ITreeView treeView, ITreeNodePropertyBinding propertyBinding, ITreeNode parent) : base(treeBuilderService, treeView, parent)
        {
            this.propertyBinding = propertyBinding;
            this.Tag = propertyBinding;
            this.allowDrop = true;

            this.propertyBinding.ImageAvailable += new ImageNodeImageAvailableHandler(NotifyImageAvailable);
        }

        public override ITreeNodeImage TreeNodeImage
        {
            get
            {
                return this.propertyBinding.TreeNodeImage;
            }

            set
            {
                this.propertyBinding.TreeNodeImage = value;
                NotifyImageAvailable(this);
            }
        }

        public override ITreeNodeBase InternalNodeObject
        {
            get
            {
                return propertyBinding;
            }
        }

        public override AbstraX.ClientInterfaces.IBase BaseObject
        {
            get 
            {
                return propertyBinding.BaseObject;
            }

            set
            {
                propertyBinding.BaseObject = value;
            }
        }

        public TreeNodePropertyType PropertyType
        {
            get
            {
                return propertyBinding.PropertyType;
            }
        }

        public TreeNodePropertyStockBinding StockBinding
        {
            get
            {
                return propertyBinding.StockBinding;
            }
        }

        public bool SourceIsURLBinding
        {
            get
            {
                return propertyBinding.SourceIsURLBinding;
            }

            set
            {
                propertyBinding.SourceIsURLBinding = value;
            }
        }

        public override void Expand()
        {
            if (!this.IsChildrenLoaded)
            {
                propertyBinding.ChildrenLoaded += new TreeBuilder.Contracts.ChildrenLoadedHandler(OnChildrenLoaded);
                propertyBinding.LoadChildren();
            }

            base.Expand();
        }

        public override string Text
        {
            get
            {
                return propertyBinding.Text;
            }

            set
            {
                propertyBinding.Text = value;
            }
        }

        public void AddMemberAsNode(object sender, RoutedEventArgs r)
        {
            var rootElement = (IElement)propertyBinding.PropertySource;
            var menu = (PopupMenuItem)sender;

            if (rootElement.Attributes.Any(a => a.Name == (string)menu.Tag))
            {
                var attribute = rootElement.Attributes.Single(a => a.Name == (string)menu.Tag);
                var createOperation = treeBuilderService.CreateAttributeNode(propertyBinding, attribute);

                createOperation.NodeCreated += (parent, e) =>
                {
                    this.Nodes.Add(new TreeBuilderTreeNodeAttributeNode(treeBuilderService, treeView, createOperation.NewNode, this) { ChildOrdinal = this.Nodes.Count });
                    base.Expand();
                };
            }
            else if (rootElement.ChildElements.Any(e => e.Name == (string)menu.Tag))
            {
                var element = rootElement.ChildElements.Single(a => a.Name == (string)menu.Tag);
                var createOperation = treeBuilderService.CreateElementNode(propertyBinding, element);

                createOperation.NodeCreated += (parent, e) =>
                {
                    this.Nodes.Add(new TreeBuilderTreeNodeElementNode(treeBuilderService, treeView, createOperation.NewNode, this) { ChildOrdinal = this.Nodes.Count });
                    base.Expand();
                };
            }
        }

        private List<IContextMenuItem> GetSubMenus()
        {
            List<IContextMenuItem> subMenus = new List<IContextMenuItem>();

            if (propertyBinding.PropertySource is IElement)
            {
                IElement element = (IElement)propertyBinding.PropertySource;

                foreach (var childElement in element.ChildElements)
                {
                    subMenus.Add(new ContextMenuItem(null, childElement.Name, childElement.Name, AddMemberAsNode));
                }
            }

            return subMenus;
        }

        public void AddFolder(object sender, RoutedEventArgs r)
        {
            var createOperation = treeBuilderService.CreateFolderNode(propertyBinding, propertyBinding.PropertySource);

            createOperation.NodeCreated += (parent, e) =>
            {
                this.Nodes.Add(new TreeBuilderTreeNodeFolder(treeBuilderService, treeView, createOperation.NewNode, this) { ChildOrdinal = this.Nodes.Count } );
                base.Expand();
            };
        }

        public override ContextMenu ContextMenu
        {
            get
            {
                if (contextMenu == null && propertyBinding.PropertyType == TreeNodePropertyType.Children)
                {
                    contextMenu = new ContextMenu
                    {
                        Items = new List<IContextMenuItem>()
                        {
                            new ContextMenuItem
                            {
                                Text = "Add Child Element as Node",
                                Items = GetSubMenus(),
                            },
                            new ContextMenuItem(null, "Add Folder", null, AddFolder),
                            new ContextMenuItem(null, "Add Query", null, AddQuery),
                            new ContextMenuItem(null, "Add Advanced Query...", null, AddAdvancedQuery),
                        }
                    };
                }

                return contextMenu;
            }

            set
            {
                contextMenu = value;
            }
        }

        public override bool? HasChildren
        {
            get { throw new NotImplementedException(); }
        }

        public override string ID
        {
            get 
            {
                return propertyBinding.ID;
            }
        }

        public override void LoadChildren()
        {
            propertyBinding.ChildrenLoaded += new TreeBuilder.Contracts.ChildrenLoadedHandler(OnChildrenLoaded);
            propertyBinding.LoadChildren();
        }

        public override IEnumerable<ITreeNodeBase> Children
        {
            get 
            {
                return propertyBinding.Children;
            }
        }

        public override void Remove()
        {
            propertyBinding.RemovedSuccessfully += (node, e) =>
            {
                this.parent.Nodes.Remove(this);
                ((TreeBuilderTreeNodeItemNode)parent).UpdatePropertyTypes();

                var op = treeBuilderService.OrphansExist();

                op.Completed += (sender, e2) =>
                {
                    if (op.Value)
                    {
                        MessageBox.Show("Orphans exist!");
                    }
                };
            };

            if (propertyBinding.TreeNodeImage != null)
            {
                if (MessageBox.Show("Delete associated image?", "Delete Image", MessageBoxButton.OKCancel) == MessageBoxResult.OK)
                {
                    var op = treeBuilderService.DeleteImage(propertyBinding.TreeNodeImage);

                    op.Completed += (sender, e) =>
                    {
                        propertyBinding.Remove();
                    };
                }
                else
                {
                    var op = treeBuilderService.DetachImage(propertyBinding.TreeNodeImage);

                    op.Completed += (sender, e) =>
                    {
                        propertyBinding.Remove();
                    };
                }
            }
            else
            {
                propertyBinding.Remove();
            }
        }

        public override bool AllowDrop
        {
            get
            {
                return allowDrop;
            }
            set
            {
                allowDrop = value;
            }
        }

        public override ITreeNode ShallowClone()
        {
            throw new NotImplementedException();
        }

		public override void OnSelect()
		{
		}
        public override ITreeNode DeepClone()
        {
            throw new NotImplementedException();
        }

        public override bool AllowRename
        {
            get
            {
                return false;
            }
            set
            {
                throw new NotImplementedException();
            }
        }

        public override void AddNew(string shortCut)
        {
        }

        public override void DragEnter(object sender, UIObjects.DragDropInterfaces.DragEventArgs e)
        {
            if (this.PropertyType == TreeNodePropertyType.Children)
            {
                var dataObject = (SW.DataObject)e.Data;
                var data = (ItemDragEventArgs)dataObject.GetData(dataObject.GetFormats().First());
                var node = (ITreeNodeBase)((SelectionCollection)data.Data).First().Item;

                if (node is ITreeNodeItemNode)
                {
                    e.Effects = UIObjects.DragDropInterfaces.DragDropEffects.Link;
                }
                else
                {
                    e.Effects = UIObjects.DragDropInterfaces.DragDropEffects.None;
                }
            }

            e.Handled = true;
        }

        public override void DragLeave(object sender, UIObjects.DragDropInterfaces.DragEventArgs e)
        {
            if (this.PropertyType == TreeNodePropertyType.Children)
            {
                var dataObject = (SW.DataObject)e.Data;
                var data = (ItemDragEventArgs)dataObject.GetData(dataObject.GetFormats().First());
                var node = (ITreeNodeBase)((SelectionCollection)data.Data).First().Item;

                if (node is ITreeNodeItemNode)
                {
                    e.Effects = UIObjects.DragDropInterfaces.DragDropEffects.Link;
                }
                else
                {
                    e.Effects = UIObjects.DragDropInterfaces.DragDropEffects.None;
                }
            }

            e.Handled = true;
        }

        public override void DragOver(object sender, UIObjects.DragDropInterfaces.DragEventArgs e)
        {
            if (this.PropertyType == TreeNodePropertyType.Children)
            {
                var dataObject = (SW.DataObject)e.Data;
                var data = (ItemDragEventArgs)dataObject.GetData(dataObject.GetFormats().First());
                var node = (ITreeNodeBase)((SelectionCollection)data.Data).First().Item;

                if (node is ITreeNodeItemNode)
                {
                    e.Effects = UIObjects.DragDropInterfaces.DragDropEffects.Link;
                }
                else
                {
                    e.Effects = UIObjects.DragDropInterfaces.DragDropEffects.None;
                }
            }

            e.Handled = true;
        }

        public override void DragStarting(object sender, UIObjects.DragDropInterfaces.ItemDragEventArgs e)
        {
        }

        public override void DragCompleted(object sender, UIObjects.DragDropInterfaces.ItemDragEventArgs e)
        {
        }

        public override void ItemDropped(object sender, UIObjects.DragDropInterfaces.ItemDragEventArgs e, int insertionIndex)
        {
            if (this.PropertyType == TreeNodePropertyType.Children)
            {
                var node = (ITreeNodeBase)((SelectionCollection)e.Data).First().Item;

                if (node is ITreeNodeItemNode)
                {
                    var createOperation = treeBuilderService.CreateShortcut(propertyBinding, node);

                    createOperation.NodeCreated += (parent, e2) =>
                    {
                        if (node is TreeBuilderTreeNodeElementNode)
                        {
                            this.Nodes.Add(new TreeBuilderTreeNodeElementNode(treeBuilderService, treeView, (ITreeNodeElementNode)createOperation.NewNode, this) { ChildOrdinal = this.Nodes.Count });
                        }
                        else if (node is TreeBuilderTreeNodeAttributeNode)
                        {
                            this.Nodes.Add(new TreeBuilderTreeNodeAttributeNode(treeBuilderService, treeView, (ITreeNodeAttributeNode)createOperation.NewNode, this) { ChildOrdinal = this.Nodes.Count });
                        }

                        base.Expand();
                    };
                }
            }

            e.Handled = true;
        }

        public override void GiveFeedback(object sender, UIObjects.DragDropInterfaces.GiveFeedbackEventArgs e)
        {
        }

        public override float ChildOrdinal
        {
            get
            {
                return propertyBinding.ChildOrdinal;
            }
            set
            {
                propertyBinding.ChildOrdinal = value;
            }
        }
    }
}
